
*		************************************************************************		*
*		************************************************************************		*
*		  File:				GermannGIQ_Analysis.do										*
*		  Date:				December 2020												*
*		  Author:			MG															*
*		  Purpose:			Internet Voting Increases Expatriate Voter Turnout			*
*		  Stata version:	14															*
*		************************************************************************		*
*		************************************************************************		*




* Set directory
cd "... \Replication Materials"




**********
** Table 1
**********

* Open data
use "GermannGIQ_Data.dta", replace

* Sample restrictions
keep if canton == "AG" | canton == "BS" | canton == "FR" | canton == "GE" | canton == "LU" ///
	| canton == "NE" | canton == "SG" | canton == "TG" 
keep if inrange(statadate,td(1jan2013),td(10feb2019))

levelsof statadate, local(dates)
gen uniquedate = .
local a = 1
foreach d of local dates {
replace uniquedate = `d' in `a'
local a = `a' + 1
}
levelsof canton, local(cantons)
foreach c of local cantons {
gen `c' = .
foreach d of local dates {
sum ivoting if canton == "`c'" & statadate == `d'
capture: replace `c' = `r(mean)' if uniquedate == `d'
}
}
format uniquedate %td
keep uniquedate AG - TG
list if uniquedate != .




**********
** Table 2
**********

* Open data
use "GermannGIQ_Data.dta", replace

* Sample restrictions
keep if canton == "AG" | canton == "BS" | canton == "FR" | canton == "GE" | canton == "LU" ///
	| canton == "NE" | canton == "SG" | canton == "TG" 
keep if inrange(statadate,td(1jan2013),td(10feb2019))

* Suspension dummy
gen suspension = 0 if ivoting == 1
replace suspension = 1 if ivoting == 0

* Model
xtreg turnout_expats suspension i.statadate, fe i(cantonid) cl(cantonid) 





**********
** Table 3
**********

* Open data
use "GermannGIQ_Data.dta", replace

* Sample restrictions
keep if canton == "AG" | canton == "BS" | canton == "FR" | canton == "GE" | canton == "LU" ///
	| canton == "NE" | canton == "SG" | canton == "TG" 
keep if inrange(statadate,td(1jan2013),td(10feb2019))

* Suspension dummy
gen suspension = 0 if ivoting == 1
replace suspension = 1 if ivoting == 0

* Define placebo treatment 1
gen placebo = 0
replace placebo = 1 if inrange(statadate,td(1jan2014),td(12aug2015)) & canton == "AG"
replace placebo = 1 if inrange(statadate,td(1jan2014),td(12aug2015)) & canton == "FR"	
replace placebo = 1 if inrange(statadate,td(1jan2014),td(12aug2015)) & canton == "SG"
replace placebo = 1 if inrange(statadate,td(1jan2014),td(12aug2015)) & canton == "TG"

* Define placebo treatment 2
gen placebo2 = 0
replace placebo2 = 1 if inrange(statadate,td(1sep2018),td(28feb2019)) & canton == "AG"
replace placebo2 = 1 if inrange(statadate,td(1sep2018),td(28feb2019)) & canton == "FR"	
replace placebo2 = 1 if inrange(statadate,td(1sep2018),td(28feb2019)) & canton == "SG"
replace placebo2 = 1 if inrange(statadate,td(1sep2018),td(28feb2019)) & canton == "TG"

* Model 1
xtreg turnout_expats suspension placebo i.statadate, fe i(cantonid) cl(cantonid) 

* Model 2
xtreg turnout_expats suspension placebo2 i.statadate, fe i(cantonid) cl(cantonid) 



**********
** Table 4
**********

* Open data
use "GermannGIQ_Data.dta", replace

* Sample restrictions
keep if canton == "AG" | canton == "BS" | canton == "FR" | canton == "GE" | canton == "LU" ///
	| canton == "NE" | canton == "SG" | canton == "TG" 
keep if inrange(statadate,td(1jan2013),td(10feb2019))

* Suspension dummy
gen suspension = 0 if ivoting == 1
replace suspension = 1 if ivoting == 0

* Unit trends (canton trends)
levelsof cantonid, local(ct)
foreach i of local ct {
gen unittrend`i' = 0
sum statadate
replace unittrend`i' = statadate - r(min) + 1 if cantonid == `i'
gen unittrendsq`i' = unittrend`i' * unittrend`i'
}
order unittrendsq*, after(unittrend25)

* Simultaneous municipal/cantonal contests
egen simultaneous = rowtotal(cantref cantelec munref munelec)

* First year of suspension vs second/third year of suspension
gen suspension_early = suspension
replace suspension_early = 0 if statadate > td(12aug2016)
gen suspension_late = suspension
replace suspension_late = 0 if statadate < td(12aug2016)


* Model 1: Linear time trends
xtreg turnout_expats suspension i.statadate unittrend3 - unittrend25, fe i(cantonid) cl(cantonid) 

* Model 2: Quadratic time trends
xtreg turnout_expats suspension i.statadate unittrend3 - unittrend25 unittrendsq3 - unittrendsq25, fe i(cantonid) cl(cantonid) 

* Model 3: Drop cases with simultaneous cantonal/municipal contests
xtreg turnout_expats suspension i.statadate if simultaneous == 0, fe i(cantonid) cl(cantonid) 

* Model 4: First vs second/third year of suspension
xtreg turnout_expats suspension_early suspension_late i.statadate, fe i(cantonid) cl(cantonid) 
test suspension_early = suspension_late

* Model 5: Restrict to 2014 onwards
xtreg turnout_expats suspension i.statadate if year >= 2014, fe i(cantonid) cl(cantonid) 

* Model 6: Restrict to 2015 onwards
xtreg turnout_expats suspension i.statadate if year >= 2015, fe i(cantonid) cl(cantonid) 

* Model 7: 2-way clustered SEs
tab statadate, gen(iddummy)
xtivreg2 turnout_expats suspension iddummy*, fe ivar(cantonid) clu(cantonid statadate)


* Model 8: Additional control cases
use "GermannGIQ_Data.dta", replace

* Sample restrictions
keep if canton == "AG" | canton == "BS" | canton == "FR" | canton == "GE" | canton == "LU" ///
	| canton == "NE" | canton == "SG" | canton == "TG" | canton == "AI" | canton == "UR" | canton == "VS"
keep if inrange(statadate,td(1jan2013),td(10feb2019))

* Suspension dummy
gen suspension = 0
replace suspension = 1 if ivoting == 0 & canton == "AG" | ivoting == 0 & canton == "FR" | ivoting == 0 & canton == "SG" | ivoting == 0 & canton == "TG" 

* Model 8
xtreg turnout_expats suspension i.statadate, fe i(cantonid) cl(cantonid) 




***********
** Figure 1
***********

* Code to reproduce the map can be obtained upon request




***********
** Figure 2
***********

* Open data
use "GermannGIQ_Data.dta", replace

* Drop missing data
keep if ivoterate != .

* Graph
twoway ///
	(scatter ivoterate statadate if canton == "AG", mcolor(ltblue) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "BE", mcolor(purple) msymbol(circle)) ///	
	(scatter ivoterate statadate if canton == "BS", mcolor(cranberry) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "FR", mcolor(black) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "GE", mcolor(gold) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "LU", mcolor(navy) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "NE", mcolor(green) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "SG", mcolor(lime) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "TG", mcolor(magenta) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "VD", mcolor(sand) msymbol(circle)) ///
	(scatter ivoterate statadate if canton == "ZH", mcolor(orange) msymbol(circle)) ///
	, ///
	yscale(noextend nofextend) ylabel(, angle(horizontal) nogrid) ///
	xtitle("", margin(large)) xscale(noextend nofextend) xlabel(18263 "2010" 20089 "2015" 21915 "2020") ///
	legend(on order(1 "Aargau" 2 "Bern" 3 "Basel-City" 4 "Fribourg" 5 "Geneva" 6 "Lucerne" ///
		7 "Neuchâtel" 8 "St. Gallen" 9 "Thurgau" 10 "Vaud" 11 "Zurich") cols(1) position(3)) ///
	ytitle("Internet votes / votes cast (%)") ///
	scheme(s2mono) scale(1.1) graphregion(fcolor(white) lcolor(white)) xsize(6) ysize(4)


* Notes on data quality (cf. Germann & Serdült 2014):	

* Cantons where i-voting was trialed but no data on usage is available
	* GL: no data on votes cast
	* GR: no data on votes cast
	* SH: no data on votes cast
	* SO: no data on votes cast
	
* Cantons with some data missing, but not all
	* BE: May 2017: limited to expats from selected municipalities and no data on total votes cast by these available
	* BE: June 2018-May2019: no data on votes cast
	* FR: March 2012
	* FR: Sep 2017 onwards not possible to separate expats & residents
	* NE: until June 2013 no data on i-votes cast
	* NE: no data on i-votes cast for June 201Bern8 and Nov 2018 onwards
	* SG: March 18 onwards not possible to separate expats & residents	
	* ZH: cannot be separated from residents in 2010/2011

* Data limitations:
	* no Wassenaar correction (until end of 2013): AG, LU, NE, SG, TG
	* BS: includes small number of disabled residents from June 2016 onwards



		
***********
** Figure 3
***********

* Open data
use "GermannGIQ_Data.dta", replace

* Sample restrictions
keep if canton == "AG" | canton == "BS" | canton == "FR" | canton == "GE" | canton == "LU" ///
	| canton == "NE" | canton == "SG" | canton == "TG" 
keep if inrange(statadate,td(1jan2013),td(10feb2019))

* Affected by suspension dummy
gen affected_2015 = 0
replace affected_2015 = 1 if canton == "AG"
replace affected_2015 = 1 if canton == "FR"	
replace affected_2015 = 1 if canton == "SG"
replace affected_2015 = 1 if canton == "TG"

collapse turnout_expats (sum) ivoting, by(affected_2015 statadate)

set obs 49
replace statadate = 20312 in 47
replace statadate = 20754 in 48
replace statadate = 21398 in 49
generate upper = 60

twoway ///
		(area upper statadate if inrange(statadate,20312,20754), bcolor(gs10) base(10) sort) ///
		(area upper statadate if inrange(statadate,20754,21398), bcolor(gs14) base(10) sort) ///
		(connected turnout_expats statadate if affected_2015 == 1, msymbol(circle) mcolor(gs0) lcolor(gs0) lpattern(solid)) ///	
		(connected turnout_expats statadate if affected_2015 == 0, msymbol(circle) mcolor(gs0) lcolor(gs0) lpattern(dash)) ///
	, ///
	ytitle("Registered" "expatriate voter turnout (%)") yscale(noextend nofextend) ylabel(10(10)60, angle(horizontal) nogrid) ymtick(10(5)60) ///
	xtitle("", margin(top)) xscale(noextend nofextend) xlabel(19359 "2013" 20089 "2015" 20820 "2017" 21550 "2019",) ///
	legend(region(lcolor(black)) order(3 "Consortium cantons" 4 "Other cantons" ) position(6) rows(1) symxsize(*.5)) ///
	scheme(s2mono) graphregion(fcolor(white) lcolor(white) ifcolor(white) ilcolor(white)) ///
	plotregion(margin(b=0 t=0)) ///
	ysize(4) xsize(6) scale(*1.3)


	

***********
** Figure 4
***********

* Open data
use "GermannGIQ_Data.dta", replace

* Sample restrictions
keep if canton == "AG" | canton == "BS" | canton == "FR" | canton == "GE" | canton == "LU" ///
	| canton == "NE" | canton == "SG" | canton == "TG" 
keep if inrange(statadate,td(1jan2013),td(10feb2019))

* Rank dates
bysort canton: egen rankdate = rank(statadate)

* Canton names
replace canton = "Aargau" if canton == "AG"
replace canton = "Basel-City" if canton == "BS"
replace canton = "Fribourg" if canton == "FR"
replace canton = "Geneva" if canton == "GE"
replace canton = "Lucerne" if canton == "LU"
replace canton = "Neuchâtel" if canton == "NE"
replace canton = "St. Gallen" if canton == "SG"
replace canton = "Thurgau" if canton == "TG"

* Graph
twoway ///
	(bar registered_expats rankdate if ivoting == 1, fcolor(gs0) fintensity(100) lcolor(gs0) barwidth(1)) ///
	(bar registered_expats rankdate if ivoting == 0, fcolor(gs16) fintensity(100) lcolor(gs0) barwidth(1)) ///
	, ///
		ytitle(# of registered expatriate voters) yscale(noextend nofextend) ylabel(, angle(horizontal) nogrid) ///
		xtitle("") xscale(noextend nofextend) xlabel(0.5 "2013" 8.5 "2015" 15.5 "2017" 22.5 "2019") ///
		by(canton, yrescale note("") graphregion(fcolor(white) lcolor(white))) subtitle(, alignment(middle) fcolor(gs12) lcolor(gs12)) ///
		legend(order(1 "Internet voting" 2 "No internet voting") symxsize(*0.5)) ///
		scheme(s2mono)
gr_edit .plotregion1.yaxis1[7].plotregion.yscale.curmin = 5600
